package vip.liux.gateway.filters.webhooks;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.data.redis.core.ReactiveHashOperations;
import org.springframework.data.redis.core.ReactiveRedisTemplate;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import vip.liux.gateway.consts.GlobalConstant;

import java.nio.charset.StandardCharsets;

@Component
public class WebhookFilter implements GlobalFilter, Ordered {

    private final ReactiveHashOperations<String, String, String> hashOperations;

    @Autowired
    public WebhookFilter(ReactiveRedisTemplate<String, String> reactiveRedisTemplate) {
        // 获取响应式Redis Hash操作对象
        this.hashOperations = reactiveRedisTemplate.opsForHash();
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String path = exchange.getRequest().getPath().toString();
        // 只拦截 /webhook/{event}/{eventId} 形式的请求
        if (path.startsWith("/webhook/")) {
            String[] parts = path.split("/");
            // 校验路径格式: /webhook/{event}/{eventId}，且 event 和 eventId 不为空且没有多余路径
            if (parts.length == 4 && !parts[2].isEmpty() && !parts[3].isEmpty()) {
                String event = parts[2];
                String eventId = parts[3];

                // 只允许POST方法
                if (HttpMethod.POST != exchange.getRequest().getMethod()) {
                    WebhookResponse error = new WebhookResponse("Method Not Allowed", -1);
                    return writeJsonResponse(exchange, HttpStatus.METHOD_NOT_ALLOWED, error);
                }

                // 判断body是否为空，不为空则读取并处理
                Flux<DataBuffer> bodyFlux = exchange.getRequest().getBody();
                // 使用hasElements()判断body流是否有内容
                return bodyFlux.hasElements().flatMap(hasBody -> {
                    if (!hasBody) {
                        WebhookResponse error = new WebhookResponse("Body is empty", -2);
                        return writeJsonResponse(exchange, HttpStatus.BAD_REQUEST, error);
                    }
                    // 有内容再合并buffer
                    return DataBufferUtils.join(bodyFlux).flatMap(dataBuffer -> {
                        byte[] bytes = new byte[dataBuffer.readableByteCount()];
                        dataBuffer.read(bytes);
                        String bodyStr = new String(bytes, StandardCharsets.UTF_8);
                        DataBufferUtils.release(dataBuffer);

                        // 存入Redis，event为hash name，eventId为key，body为value
                        return hashOperations.put("webhooks:" + event, eventId, bodyStr)
                                .flatMap(res -> {
                                    WebhookResponse result = new WebhookResponse("ok", 0);
                                    return writeJsonResponse(exchange, HttpStatus.OK, result);
                                });
                    }).onErrorResume(e -> {
                        WebhookResponse error = new WebhookResponse("Failed to parse body", -3);
                        return writeJsonResponse(exchange, HttpStatus.INTERNAL_SERVER_ERROR, error);
                    });
                });
            } else {
                // 路径格式不正确
                WebhookResponse error = new WebhookResponse("Not Found", -1);
                return writeJsonResponse(exchange, HttpStatus.NOT_FOUND, error);
            }
        }
        // 非webhook请求，交给下一个过滤器
        return chain.filter(exchange);
    }

    /**
     * 输出JSON响应
     *
     * @param exchange ServerWebExchange
     * @param status   HTTP状态码
     * @param obj      响应内容
     * @return 写出响应的Mono
     */
    private Mono<Void> writeJsonResponse(ServerWebExchange exchange, HttpStatus status, WebhookResponse obj) {
        try {
            exchange.getResponse().setStatusCode(status);
            exchange.getResponse().getHeaders().set("Content-Type", "application/json;charset=UTF-8");
            byte[] response = GlobalConstant.writeValueAsBytes(obj);
            DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(response);
            return exchange.getResponse().writeWith(Mono.just(buffer));
        } catch (Exception e) {
            // 兜底返回系统错误
            exchange.getResponse().setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
            byte[] response = ("{\"msg\":\"Internal Server Error\",\"code\":-1}").getBytes(StandardCharsets.UTF_8);
            DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(response);
            return exchange.getResponse().writeWith(Mono.just(buffer));
        }
    }

    @Override
    public int getOrder() {
        // 优先级设为最高（负数值越高优先级越高）
        return -1000;
    }

    /**
     * 统一Webhook响应结构
     */
    public record WebhookResponse(String msg, int code) {
    }
}